#include "stdafx.h"
#include "simplelistctrl.h"




BEGIN_MESSAGE_MAP(CSimpleListCtrl, CListCtrl)
//{{AFX_MSG_MAP(myList)
ON_WM_CREATE()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()

int CSimpleListCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
	if (CListCtrl::OnCreate(lpCreateStruct) == -1)
		return -1;
	
	// TODO: Add your specialized creation code here
	this->SetDefaultStyle();
	
	return 0;
}

BOOL CSimpleListCtrl::SetHeads( const CString& strHeadings )
{
	int iStart = 0;

	for ( ;; )
	{
		const int iComma = strHeadings.Find( _T(','), iStart );

		if ( iComma == -1 )
			break;

		const CString strHeading = strHeadings.Mid( iStart, iComma - iStart );

		iStart = iComma + 1;

		int iSemiColon = strHeadings.Find( _T(';'), iStart );

		if ( iSemiColon == -1 )
			iSemiColon = strHeadings.GetLength();

		const int iWidth = _tstoi( strHeadings.Mid( iStart, iSemiColon - iStart ) );

		iStart = iSemiColon + 1;

		if ( InsertColumn( m_iNumColumns++, strHeading, LVCFMT_LEFT,/* iWidth*/iWidth ) == -1 )
		{
			return FALSE;
		}
	}

	return TRUE;
}

int CSimpleListCtrl::InsertValues( int pos, LPCTSTR pszText, ... )
{
	const int iIndex = pos;

	InsertItem( iIndex, pszText );


	va_list list;
	va_start( list, pszText );

	for ( int iColumn = 1; iColumn < m_iNumColumns; iColumn++ )
	{
		pszText = va_arg( list, LPCTSTR );
		VERIFY( CListCtrl::SetItem( iIndex, iColumn, LVIF_TEXT, pszText, 0, 0, 0, 0 ) );
	}

	va_end( list );		
	return iIndex;
}

void CSimpleListCtrl::AddCheckBoxStyle()
{
	this->AddStyle(LVS_EX_CHECKBOXES);
}

void CSimpleListCtrl::AddStyle( DWORD newstyle )
{
	DWORD style = this->GetExtendedStyle() | newstyle;
	this->SetExtendedStyle(style);
}

CSimpleListCtrl::CSimpleListCtrl()
{
	m_iNumColumns = 0;
}

CSimpleListCtrl::~CSimpleListCtrl()
{

}

void CSimpleListCtrl::SetDefaultStyle()
{
	this->ModifyStyle(0,LVS_REPORT);
	DWORD style =  this->GetExtendedStyle() | LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES ;
	this->SetExtendedStyle(style);
	this->ShowScrollBar(SB_BOTH   ,SW_SHOW);	
}

int CSimpleListCtrl::AddLine( CStringArray& Array )
{
	int pos = GetItemCount();
	const int iIndex = pos;

	InsertItem( iIndex, Array[0] );
	for ( int iColumn = 1; iColumn < m_iNumColumns; iColumn++ )
	{
		VERIFY( CListCtrl::SetItem( iIndex, iColumn, LVIF_TEXT, Array[iColumn], 0, 0, 0, 0 ) );
	}

	return iIndex;
}

int CSimpleListCtrl::AddLine( LPCTSTR pszText, ... )
{
	int pos = GetItemCount();

	const int iIndex = pos;

	InsertItem( iIndex, pszText );


	va_list list;
	va_start( list, pszText );
	for ( int iColumn = 1; iColumn < m_iNumColumns; iColumn++ )
	{
		pszText = va_arg( list, LPCTSTR );		
		VERIFY( CListCtrl::SetItem( iIndex, iColumn, LVIF_TEXT, pszText, 0, 0, 0, 0 ) );
	}

	va_end( list );		
	return iIndex;
}

CString CSimpleListCtrl::GetItemValue( int row,int column ) const
{
	CString buff;

	GetItemText( row,column,buff.GetBuffer(256) , 256);
	buff.ReleaseBuffer();
	return buff;
}


BOOL CSimpleListCtrl::GetlineValues( int row,std::vector<CString>* pret )
{
	if ( row >= this->GetItemCount()) 
		return FALSE;

	pret->clear();
	for (int i=0; i<m_iNumColumns; i++)
	{
		pret->push_back( GetItemValue(row,i) );
	}
	return TRUE;
}

BOOL CSimpleListCtrl::SetItemValue( int row,int column,const CString& itemVal )
{
	if (column>= m_iNumColumns || row >= GetLinesCount())
	{
		return FALSE;
	}
	SetItemText(row,column,itemVal);
	return TRUE;
}

int CSimpleListCtrl::GetFirstSelectLinePos()
{
	int count = GetSelectedCount();
	if (count == 0)
	{
		return -1;
	}
	POSITION pos = GetFirstSelectedItemPosition();		
	int Index = GetNextSelectedItem(pos);
	return Index;
}

BOOL CSimpleListCtrl::GetSelectlineValues( std::vector<CString>* pVec )
{
	int Index = GetFirstSelectLinePos();
	if (Index == -1)
	{
		return FALSE;
	}
	return GetlineValues(Index,pVec);
}

int CSimpleListCtrl::GetLinesCount() const
{
	return this->GetItemCount();
}

int CSimpleListCtrl::GetColumns() const
{
	return m_iNumColumns;
}



void CSimpleListCtrl::AdjustColumnWidth()
{
	SetRedraw(FALSE);
	int nColumnCount = this->GetColumns();

	for (int i = 0; i < nColumnCount; i++)
	{
		SetColumnWidth(i, LVSCW_AUTOSIZE);
		int nColumnWidth =this-> GetColumnWidth(i);
		SetColumnWidth(i, LVSCW_AUTOSIZE_USEHEADER);
		int nHeaderWidth = GetColumnWidth(i);
		SetColumnWidth(i, max(nColumnWidth, nHeaderWidth));
	}
	SetRedraw(TRUE);
}











//#include <windowsx.h>


#define IDC_EDIT  0X01
#define PROPERTY_ITEM 0x02
#define PROPERTY_SUB  0x03
/////////////////////////////////////////////////////////////////////////////
// CEditListCtrl

CEditListCtrl::CEditListCtrl()
{
   m_edit.m_hWnd = NULL;	
}

CEditListCtrl::~CEditListCtrl()
{

}


BEGIN_MESSAGE_MAP(CEditListCtrl, CListCtrl)
	//{{AFX_MSG_MAP(CEditListCtrl)
	ON_WM_LBUTTONDBLCLK()
	ON_WM_PARENTNOTIFY()
	//}}AFX_MSG_MAP
	ON_MESSAGE(WM_USER_EDIT_END,OnEditEnd)
END_MESSAGE_MAP()


void CEditListCtrl::OnLButtonDblClk(UINT nFlags, CPoint point) 
{
	CRect rcCtrl;
	LVHITTESTINFO lvhti;
    lvhti.pt = point;
	int nItem = CListCtrl::SubItemHitTest(&lvhti);
	if(nItem == -1)
	   return;
	int nSubItem = lvhti.iSubItem;
	CListCtrl::GetSubItemRect(nItem,nSubItem,LVIR_LABEL,rcCtrl); 
    ShowEdit(TRUE,nItem,nSubItem,rcCtrl);
	CListCtrl::OnLButtonDblClk(nFlags, point);
}
void CEditListCtrl::ShowEdit(BOOL bShow,int nItem,int nIndex,CRect rcCtrl)
{
    if(m_edit.m_hWnd == NULL)
	{
		m_edit.Create(ES_AUTOHSCROLL|WS_CHILD|ES_LEFT|ES_WANTRETURN|WS_BORDER,CRect(0,0,0,0),this,IDC_EDIT);
		m_edit.ShowWindow(SW_HIDE);

		CFont tpFont;
		tpFont.CreateStockObject(DEFAULT_GUI_FONT);
		m_edit.SetFont(&tpFont);
		tpFont.DeleteObject();
	}
	if(bShow == TRUE)
	{
		CString strItem = CListCtrl::GetItemText(nItem,nIndex);
		m_edit.MoveWindow(rcCtrl);
		m_edit.ShowWindow(SW_SHOW);
		m_edit.SetWindowText(strItem);
		::SetFocus(m_edit.GetSafeHwnd());
		m_edit.SetSel(-1);  
		m_edit.SetCtrlData(MAKEWPARAM(nIndex,nItem));	
	}
	else
		m_edit.ShowWindow(SW_HIDE);
}
LRESULT CEditListCtrl::OnEditEnd(WPARAM wParam,LPARAM lParam)
{
	if(wParam == TRUE)
	{
		CString strText(_T(""));
		m_edit.GetWindowText(strText);
		DWORD dwData = m_edit.GetCtrlData();
		int nItem= dwData>>16;
		int nIndex = dwData&0x0000ffff;
		CListCtrl::SetItemText(nItem,nIndex,strText);
	}
	else
	{
	   
	}

    if(lParam == FALSE)
	    m_edit.ShowWindow(SW_HIDE);
	return 0;
}

void CEditListCtrl::OnParentNotify(UINT message, LPARAM lParam) 
{
	CListCtrl::OnParentNotify(message, lParam);
	//////////////////////////////////////////////////////////////////////////
	CHeaderCtrl* pHeaderCtrl = CListCtrl::GetHeaderCtrl();
	if(pHeaderCtrl == NULL)
		return;
	CRect rcHeader;
	pHeaderCtrl->GetWindowRect(rcHeader);
	ScreenToClient(rcHeader);
	//The x coordinate is in the low-order word and the y coordinate is in the high-order word.
	CPoint pt;
	pt.x = GET_X_LPARAM(lParam);
	pt.y = GET_Y_LPARAM(lParam);
	if(rcHeader.PtInRect(pt) && message == WM_LBUTTONDOWN)
	{
		if(m_edit.m_hWnd != NULL)
		{
			DWORD dwStyle = m_edit.GetStyle();
			if((dwStyle&WS_VISIBLE) == WS_VISIBLE)
			{
				m_edit.ShowWindow(SW_HIDE);
			}
		}	
	}	
}
BOOL CEditListCtrl::PreTranslateMessage(MSG* pMsg) 
{
	if(pMsg->message == WM_KEYDOWN)
	{
		if(pMsg->wParam == VK_TAB && m_edit.m_hWnd!= NULL)
		{
		 	DWORD dwStyle = m_edit.GetStyle();
			if((dwStyle&WS_VISIBLE) == WS_VISIBLE)
			{
			     OnEditEnd(TRUE,TRUE);
				 CRect rcCtrl;		 
				 int nItem;
				 int nSub;
				 if(FALSE == Key_Ctrl(nItem,nSub))
                    Key_Shift(nItem,nSub);
                 CListCtrl::GetSubItemRect(nItem,nSub,LVIR_LABEL,rcCtrl); 
				 CPoint pt(rcCtrl.left+1,rcCtrl.top+1);
				 OnLButtonDblClk(0,pt);
				 POSITION pos = CListCtrl::GetFirstSelectedItemPosition();
				 if (pos == NULL)
				 {
				 }
				 else
				 {
					 while (pos)
					 {
						 int ntpItem = CListCtrl::GetNextSelectedItem(pos);
						 CListCtrl::SetItemState(ntpItem,0,LVIS_SELECTED);
					 }
				 }
				 CListCtrl::SetItemState(nItem,  LVIS_SELECTED,  LVIS_SELECTED);
				 return TRUE;
			}
		}
		if (pMsg->wParam == VK_DELETE && (m_edit.m_hWnd == NULL || m_edit.IsWindowVisible() == FALSE) )
		{
			if ( GetSelectedCount() != 0 )
			{
				POSITION pos = GetFirstSelectedItemPosition();				
				int Index = GetNextSelectedItem(pos);
				DeleteItem(Index);
				return TRUE;
			}
			
		}
	}
	
	return CListCtrl::PreTranslateMessage(pMsg);
}
BOOL CEditListCtrl::Key_Shift(int& nItem,int& nSub)
{
	int nItemCount = CListCtrl::GetItemCount();
	DWORD dwData = m_edit.GetCtrlData();
	nItem= dwData>>16;
	nSub = dwData&0x0000ffff;
	
	CHeaderCtrl* pHeader = CListCtrl::GetHeaderCtrl();
	if(pHeader == NULL)
		return FALSE;
	
	short sRet = GetKeyState(VK_SHIFT);
	int nSubcCount = pHeader->GetItemCount();
	sRet = sRet >>15;
	if(sRet == 0)
	{
		nSub += 1;
		if(nSub >= nSubcCount)
		{
			if(nItem == nItemCount-1)
			{
				nItem = 0;
				nSub  = 0;
			}
			else
			{
				nSub = 0;
				nItem += 1;
			}
		}
		if(nItem >= nItemCount)
			nItem = nItemCount-1;
		return FALSE;
	}
	else
	{
		nSub -= 1;
		if(nSub < 0)
		{
			
			nSub = nSubcCount -1;
			nItem --;
		}
		
		if(nItem < 0)
			nItem = nItemCount-1;
		return TRUE;
		
	}
	return FALSE;
}
BOOL CEditListCtrl::Key_Ctrl(int& nItem,int &nSub)
{
    short sRet = GetKeyState(VK_CONTROL);
	DWORD dwData = m_edit.GetCtrlData();
	nItem= dwData>>16;
	nSub = dwData&0x0000ffff;
	
	sRet = sRet >>15;
	int nItemCount = CListCtrl::GetItemCount();
	if(sRet == 0)
	{
		
	}
	else
	{
		nItem = nItem >=nItemCount-1? 0:nItem+=1;
		return TRUE;
	}
	
	return FALSE;
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////

CListCtrlEdit::CListCtrlEdit()
{
}

CListCtrlEdit::~CListCtrlEdit()
{
}


BEGIN_MESSAGE_MAP(CListCtrlEdit, CEdit)
	//{{AFX_MSG_MAP(CListCtrlEdit)
	ON_WM_KILLFOCUS()
	ON_WM_SETFOCUS()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CListCtrlEdit message handlers
void CListCtrlEdit::SetCtrlData(DWORD dwData)
{
	m_dwData = dwData;
}

DWORD CListCtrlEdit::GetCtrlData()
{
   return m_dwData;
}

void CListCtrlEdit::OnKillFocus(CWnd* pNewWnd) 
{
	CEdit::OnKillFocus(pNewWnd);
	CWnd* pParent = this->GetParent();
	::PostMessage(pParent->GetSafeHwnd(),WM_USER_EDIT_END,m_bExchange,0);
}
BOOL CListCtrlEdit::PreTranslateMessage(MSG* pMsg) 
{
	
	if(pMsg->message == WM_KEYDOWN)
	{
		if(pMsg->wParam == VK_RETURN)
		{
			CWnd* pParent = this->GetParent();
			m_bExchange = TRUE;
			::PostMessage(pParent->GetSafeHwnd(),WM_USER_EDIT_END,m_bExchange,0);
		}
		else if(pMsg->wParam == VK_ESCAPE)
		{
           CWnd* pParent = this->GetParent();
		   m_bExchange = FALSE;
			::PostMessage(pParent->GetSafeHwnd(),WM_USER_EDIT_END,m_bExchange,0);
		}
	}
	
	return CEdit::PreTranslateMessage(pMsg);
}

void CListCtrlEdit::OnSetFocus(CWnd* pOldWnd) 
{
	CEdit::OnSetFocus(pOldWnd);
    m_bExchange = TRUE;	
}











#ifdef _DEBUG
#define ASSERT_VALID_STRING( str ) ASSERT( !IsBadStringPtr( str, 0xfffff ) )
#else	//	_DEBUG
#define ASSERT_VALID_STRING( str ) ( (void)0 )
#endif	//	_DEBUG

struct ItemData
{
public:
	ItemData() : arrpsz( NULL ), dwData( NULL )
	{}

	LPTSTR* arrpsz;
	DWORD dwData;

private:
	// ban copying.
	ItemData( const ItemData& );
	ItemData& operator=( const ItemData& );
};



BEGIN_MESSAGE_MAP(CSortableListCtrl, CSimpleListCtrl)
	//{{AFX_MSG_MAP(CSortListCtrl)
	ON_NOTIFY_REFLECT(LVN_COLUMNCLICK, OnColumnClick)
	//ON_WM_DESTROY()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

int CSortableListCtrl::CompareFunction( LPARAM lParam1, LPARAM lParam2, LPARAM lParamData )
{
	CSortableListCtrl* pListCtrl = reinterpret_cast<CSortableListCtrl*>( lParamData );
	ASSERT( pListCtrl->IsKindOf( RUNTIME_CLASS( CListCtrl ) ) );

	ItemData* pid1 = reinterpret_cast<ItemData*>( lParam1 );
	ItemData* pid2 = reinterpret_cast<ItemData*>( lParam2 );

	ASSERT( pid1 );
	ASSERT( pid2 );

	LPCTSTR pszText1 = pid1->arrpsz[ pListCtrl->m_iSortColumn ];
	LPCTSTR pszText2 = pid2->arrpsz[ pListCtrl->m_iSortColumn ];

	ASSERT_VALID_STRING( pszText1 );
	ASSERT_VALID_STRING( pszText2 );

	return pListCtrl->m_bSortAscending ? lstrcmp( pszText1, pszText2 ) : lstrcmp( pszText2, pszText1 );
}
BOOL CSortableListCtrl::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT *pResult)
{
	switch (((NMHDR*)lParam)->code)
	{
	case HDN_BEGINTRACKW:
	case HDN_BEGINTRACKA:
		*pResult = TRUE;                // disable tracking
		return TRUE;                    // Processed message
	}

	return CListCtrl::OnNotify(wParam, lParam, pResult);

}

void CSortableListCtrl::Sort( int iColumn, BOOL bAscending )
{
	m_iSortColumn = iColumn;
	m_bSortAscending = bAscending;

	// show the appropriate arrow in the header control.
	m_ctlHeader.SetSortArrow( m_iSortColumn, m_bSortAscending );

	VERIFY( SortItems( CompareFunction, reinterpret_cast<DWORD>( this ) ) );
}

void CSortableListCtrl::OnColumnClick( NMHDR* pNMHDR, LRESULT* pResult )
{
	NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
	const int iColumn = pNMListView->iSubItem;

	// if it's a second click on the same column then reverse the sort order,
	// otherwise sort the new column in ascending order.
	Sort( iColumn, iColumn == m_iSortColumn ? !m_bSortAscending : TRUE );

	*pResult = 0;
}

void CSortableListCtrl::SetSortAble()
{
	ASSERT( GetStyle() & LVS_REPORT );

	CListCtrl::PreSubclassWindow();
	VERIFY( m_ctlHeader.SubclassWindow( GetHeaderCtrl()->GetSafeHwnd() ) );
}
